
#ifndef __TCP_SERVER_H
#define __TCP_SERVER_H

#include <openssl/err.h>
#include <apr.h>
#include <apr_atomic.h>
#include <apr_file_io.h>
#include <apr_poll.h>
#include <apr_portable.h>
#include "../aprtools/APRMutex.h"
#include "../aprtools/APRBucketBrigade.h"
#include "netgeneral.h"

/** A struct shared between threads, a collection of pointers to pipes
 * which allow communication between the listening server side and the
 * client handlers. The pointers on the pipes are NULL on an inactive,
 * waiting listening thread. */
typedef struct clientpipestreams
{
   /** The memory pool local to this thread. */
   apr_pool_t *localmp;
   /** The socket address associated with the client connected on this
    * thread. */
   apr_sockaddr_t *cliaddr;
   /** The pipe from the listening socket to the serving thread. */
   APRBucketBrigade *recv_to_handler;
   /** The pipe from the serving thread back to the listening
    * thread. */
   APRBucketBrigade *handler_to_send;
   /** Client socket pointer. */
   apr_socket_t *clisock;
   /** Mutex for starting sessions. */
   APRMutex *sessionstart;
   /** Mutex to wait on when the thread is inactive. */
   APRMutex *waiting;
} ClientPipeStreams;

/** A basic TCP server class. This is the base class for all types of
 * servers. */
class TCPServer
{
   public:
      TCPServer(int inoofthreads, int iportno, const char *ihostname, apr_pool_t *upperpool);
      virtual ~TCPServer();
      int startListeningThread();
      int startSessionThreads();
      const char *getClientAddressAsStaticString(int threadid);
      /** Is the TCP server listening? */
      int isListening() { return (!listenstop); }
   protected:
      /** Pointer to an array of client pipes. */
      ClientPipeStreams *pipearray;
      /** The one listening thread. */
      apr_thread_t *listening_thread;
      /** The many per-session client threads. */
      apr_thread_t **session_threads;
      /** The thread attributes for the one listening thread. */
      apr_threadattr_t *listening_attr;
      /** The many thread attributes for the many client threads. */
      apr_threadattr_t **session_threadattrs;
      /** The memory pool. */
      apr_pool_t *mp;
      /** The number of client threads. */
      int noofthreads;
   private:
      void acceptIncomingOnSocket(apr_pollset_t *pollset, apr_socket_t *lsock, apr_pool_t *mp);
      void handleServerListening(apr_pool_t *localmp);
      static void *handleServerListeningStatic(apr_thread_t *tthread, void *vthis);
      void handleClientsOnThread(int threadid, apr_pool_t *localmp);
      static void *handleClientsOnThreadStatic(apr_thread_t *tthread, void *args);
      /** Get the client handler as a function pointer. */
      virtual functor getClientHandlerFunction() const { return (functor)(&handleClientsOnThreadStatic); }
      int joinThreads();
      apr_socket_t *createListeningSocket(apr_pool_t *mp);
      /** Hostname for the listening server. */
      char *hostname;
      /** Port number for the listening server. */
      int portno;
      /** The time out for the listening server. */
      int timeout;
      /** Flag to be set by the listen to stop. */
      int listenstop;
   protected:
      /** Flag to be set by the server */
      int sessionstop;
};

#endif
